﻿//-----------------------------------------------------------------------
// <copyright file="MainForm.cs" company="Nathan Miller">
// Copyright (c) Nathan Miller.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
//-----------------------------------------------------------------------
namespace TileTool.Base.UI.MainWindow
{
    using System;
    using System.Windows.Forms;
    using TileTool.Base.Editor.Grid;
    using TileTool.Editor.Command;
    using TileTool.Editor.Grid;
    using TileTool.Editor.Transform;
    using TileTool.Message;
    using TileTool.Render;
    using TileTool.UI.MainWindow;

    /// <summary>
    /// Main application form.
    /// </summary>
    public partial class MainForm : Form
    {
        #region Fields - Private

        /// <summary>
        /// Main window creation data.
        /// </summary>
        private MainWindowCreateData windowCreateData;

        /// <summary>
        /// Message router to use. Comes from the MainWindowCreateData class.
        /// </summary>
        private MessageRouter router;

        /// <summary>
        /// Transform state to use. Comes from the MainWindowCreateData class.
        /// </summary>
        private ITransformState state;

        #endregion

        #region Constructor

        /// <summary>
        /// Form constructor for the form designer.
        /// </summary>
        public MainForm()
        {
            this.InitializeComponent();
        }

        /// <summary>
        /// Form constructor for application runtime.
        /// </summary>
        /// <param name="createData">Main window creation data.</param>
        public MainForm(MainWindowCreateData createData)
        {
            if (createData == null)
            {
                throw new ArgumentNullException("createData", "Create data must be non-null.");
            }

            createData.Validate();
            this.windowCreateData = createData;
            this.router = this.windowCreateData.Router;
            this.state = this.windowCreateData.State;

            this.InitializeComponent();

            ICanvas canvas = createData.Canvas;

            this.tableLayoutPanel1.Controls.Add(canvas.Control);

            this.toolStripSnapToGridButton.Checked = this.state.SnapState.SnapToGrid;
            this.toolStripTranslateSnapButton.Checked = this.state.SnapState.TranslateSnap;
            this.toolStripTranslateSnapTextBox.Text = this.state.SnapState.TranslateSnapAmount.ToString();
            this.toolStripRotateSnapButton.Checked = this.state.SnapState.RotateSnap;
            this.toolStripRotateSnapTextBox.Text = this.state.SnapState.RotateSnapDegrees.ToString();

            this.SetupCoordinateSystemCombo();

            this.RegisterForMessages();
        }

        #endregion

        #region Methods - Private

        /// <summary>
        /// Register for messages we are interested in.
        /// </summary>
        private void RegisterForMessages()
        {
            ITransformState transform = this.windowCreateData.State;
            TileTool.Message.IMessageFilter snapFilter = new GenericMessageFilter<SnapStateChangedMessage, ISnapState>(
                transform.SnapState, (msg) => { return msg.SnapState; });

            this.router.RegisterForMessage<SnapStateChangedMessage>(
                this.HandleSnapStateChangedMessage, snapFilter);
        }

        /// <summary>
        /// Setup the coordinate system combo box.
        /// </summary>
        private void SetupCoordinateSystemCombo()
        {
            foreach (CoordinateSystem system in Enum.GetValues(typeof(CoordinateSystem)))
            {
                this.toolStripCoordSystem.Items.Add(system);
            }

            this.toolStripCoordSystem.SelectedIndex = (int)this.state.System;
        }

        #endregion

        #region Methods - Private - Message handlers

        /// <summary>
        /// Handle a grid state changed message.
        /// </summary>
        /// <param name="msg">Message to handle.</param>
        /// <returns>MessageHandlerResult for if we handled the message.</returns>
        private MessageHandlerResult HandleSnapStateChangedMessage(SnapStateChangedMessage msg)
        {
            this.toolStripSnapToGridButton.Checked = msg.SnapState.SnapToGrid;
            this.toolStripTranslateSnapButton.Checked = msg.SnapState.TranslateSnap;
            this.toolStripRotateSnapButton.Checked = msg.SnapState.RotateSnap;
            this.toolStripTranslateSnapTextBox.Text = this.state.SnapState.TranslateSnapAmount.ToString();
            this.toolStripRotateSnapTextBox.Text = this.state.SnapState.RotateSnapDegrees.ToString();

            return MessageHandlerResult.Ignored;
        }

        #endregion

        #region Methods - Private - UI event handlers

        /// <summary>
        /// Handle undo button click.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void ToolStripUndoButton_Click(object sender, EventArgs e)
        {
            CommandIdMessage msg = new CommandIdMessage();

            msg.Command = EditorCommandIds.UndoCommand;

            this.windowCreateData.Router.SendMessage(msg);
        }

        /// <summary>
        /// Handle redo button click.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void ToolStripRedoButton_Click(object sender, EventArgs e)
        {
            CommandIdMessage msg = new CommandIdMessage();

            msg.Command = EditorCommandIds.RedoCommand;

            this.windowCreateData.Router.SendMessage(msg);
        }

        /// <summary>
        /// Handle snap to grid button click.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void ToolStripSnapToGridButton_Click(object sender, EventArgs e)
        {
            CommandIdMessage msg = new CommandIdMessage();

            msg.Command = EditorCommandIds.ToggleSnapToGridCommand;

            this.windowCreateData.Router.SendMessage(msg);
        }

        /// <summary>
        /// Handle translate snap button click.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void ToolStripTranslateSnapButton_Click(object sender, EventArgs e)
        {
            CommandIdMessage msg = new CommandIdMessage();

            msg.Command = EditorCommandIds.ToggleTranslateSnapCommand;

            this.windowCreateData.Router.SendMessage(msg);
        }

        /// <summary>
        /// Handle rotate snap button click.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void ToolStripRotateSnapButton_Click(object sender, EventArgs e)
        {
            CommandIdMessage msg = new CommandIdMessage();

            msg.Command = EditorCommandIds.ToggleRotateSnapCommand;

            this.windowCreateData.Router.SendMessage(msg);
        }

        /// <summary>
        /// Coordinate system selection changed.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void ToolStripCoordSystem_SelectedIndexChanged(object sender, EventArgs e)
        {
            int index = this.toolStripCoordSystem.SelectedIndex;
            
            if (!Enum.IsDefined(typeof(CoordinateSystem), index))
            {
                return;
            }

            CoordinateSystem system = (CoordinateSystem)index;
            CommandIdMessage msg = new CommandIdMessage();

            msg.Command = EditorCommandIds.SetCoordinateSystemCommand;
            msg.SetParams(system);

            this.windowCreateData.Router.SendMessage(msg);
        }

        /// <summary>
        /// Handle copy button click.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void ToolStripCopyButton_Click(object sender, EventArgs e)
        {
            CommandIdMessage msg = new CommandIdMessage();

            msg.Command = EditorCommandIds.CopyCommand;

            this.windowCreateData.Router.SendMessage(msg);
        }

        /// <summary>
        /// Handle copy button click.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void ToolStripPasteButton_Click(object sender, EventArgs e)
        {
            CommandIdMessage msg = new CommandIdMessage();

            msg.Command = EditorCommandIds.PasteCommand;

            this.windowCreateData.Router.SendMessage(msg);
        }

        /// <summary>
        /// Handle create group click.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void CreateGroupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CommandIdMessage msg = new CommandIdMessage();

            msg.Command = EditorCommandIds.CreateGroupCommand;

            this.windowCreateData.Router.SendMessage(msg);
        }

        /// <summary>
        /// Handle delete group click.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void DeleteGroupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CommandIdMessage msg = new CommandIdMessage();

            msg.Command = EditorCommandIds.DestroyGroupCommand;

            this.windowCreateData.Router.SendMessage(msg);
        }

        /// <summary>
        /// Handle add selected to group.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void AddSelectedToGroupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CommandIdMessage msg = new CommandIdMessage();

            msg.Command = EditorCommandIds.AddToGroupCommand;

            this.windowCreateData.Router.SendMessage(msg);
        }

        /// <summary>
        /// Handle remove selected from group.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void RemoveSelectedFromGroupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CommandIdMessage msg = new CommandIdMessage();

            msg.Command = EditorCommandIds.RemoveFromGroupCommand;

            this.windowCreateData.Router.SendMessage(msg);
        }

        /// <summary>
        /// Handle open / close from group.
        /// </summary>
        /// <param name="sender">Event sender.</param>
        /// <param name="e">Event arguments.</param>
        private void OpenCloseGroupToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CommandIdMessage msg = new CommandIdMessage();

            msg.Command = EditorCommandIds.ToggleGroupOpenCloseCommand;

            this.windowCreateData.Router.SendMessage(msg);
        }

        #endregion
    }
}
